#include <arpa/inet.h>
#include <cstring>
#include <iostream>
#include <sys/poll.h>  // 包含poll相关头文件
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h> 

int main() {
    // 1. 创建 TCP 监听套接字
    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd < 0) {
        perror("socket");
        return 1;
    }

    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(8080);
    
    // 绑定地址和端口
    if (bind(listen_fd, (sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("bind");
        close(listen_fd);
        return 1;
    }
    
    // 开始监听
    if (listen(listen_fd, 5) < 0) {
        perror("listen");
        close(listen_fd);
        return 1;
    }

    // 2. 把 listen_fd 设为非阻塞
    fcntl(listen_fd, F_SETFL, O_NONBLOCK);

    std::cout << "Listening on 0.0.0.0:8080, press q+Enter to quit\n";

    // 3. 初始化pollfd结构体数组，包含要监听的文件描述符
    struct pollfd fds[2];  // 监听两个fd：标准输入和监听套接字
    fds[0].fd = STDIN_FILENO;       // 标准输入
    fds[0].events = POLLIN;         // 关注可读事件
    fds[0].revents = 0;             // 用于返回实际发生的事件

    fds[1].fd = listen_fd;          // 监听套接字
    fds[1].events = POLLIN;         // 关注可读事件（有新连接）
    fds[1].revents = 0;

    while (true) {
        // 4. 调用poll，阻塞等待事件发生，超时时间设为-1表示无限等待
        int ready = poll(fds, 2, -1);
        if (ready < 0) {
            perror("poll");
            break;
        } else if (ready == 0) {
            // 超时（这里不会发生，因为超时时间设为-1）
            continue;
        }

        // 5. 检查事件发生的文件描述符
        // 检查标准输入
        if (fds[0].revents & POLLIN) {
            char buf[128];
            if (fgets(buf, sizeof(buf), stdin)) {
                if (buf[0] == 'q') {
                    std::cout << "Quit by user\n";
                    break;
                }
            }
            // 重置事件标志
            fds[0].revents = 0;
        }

        // 检查监听套接字（新连接）
        if (fds[1].revents & POLLIN) {
            sockaddr_in client_addr{};
            socklen_t len = sizeof(client_addr);
            int conn_fd = accept(listen_fd, (sockaddr *)&client_addr, &len);
            if (conn_fd >= 0) {
                std::cout << "New connection from "
                          << inet_ntoa(client_addr.sin_addr) << ":"
                          << ntohs(client_addr.sin_port) << "\n";
                close(conn_fd);  // 简单示例：直接关闭连接
            }
            // 重置事件标志
            fds[1].revents = 0;
        }
    }

    close(listen_fd);
    return 0;
}
